(function( $, undefined ) {

var mouseHandled = false;
$( document ).mouseup( function() {
  mouseHandled = false;
});

$.widget("core.mouse", {
  version: "@VERSION",
  options: {
    //cancel: "input,textarea,button,select,option",
    distance: 1,
    delay: 0
  },
  _mouseInit: function() {
    var that = this;

    $(this.element, FrameDocument).bind("mousedown."+this.widgetName, function(event) {
        return that._mouseDown(event);
    });
    //$(document).on('click', 'body', function(event) {
    $(this.element, FrameDocument).bind("click."+this.widgetName, function(event) {
      if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
        $.removeData(event.target, that.widgetName + ".preventClickEvent");
        event.stopImmediatePropagation();
        return false;
      }
    });
    /*
      .bind("click."+this.widgetName, function(event) {
        if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
          $.removeData(event.target, that.widgetName + ".preventClickEvent");
          event.stopImmediatePropagation();
          return false;
        }
      });
    */

    this.started = false;
  },

  // TODO: make sure destroying one instance of mouse doesn't mess with
  // other instances of mouse
  _mouseDestroy: function() {
    this.element.unbind("."+this.widgetName);
    if ( this._mouseMoveDelegate ) {
      $(FrameDocument)
        .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
        .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
    }
  },

  _mouseDown: function(event) {
    // don't let more than one widget handle mouseStart
    if( mouseHandled ) { return; }

    // we may have missed mouseup (out of window)
    (this._mouseStarted && this._mouseUp(event));

    this._mouseDownEvent = event;

    var that = this,
      btnIsLeft = (event.which === 1),
      // event.target.nodeName works around a bug in IE 8 with
      // disabled inputs (#7620)
      elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
    if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
      return true;
    }

    this.mouseDelayMet = !this.options.delay;
    if (!this.mouseDelayMet) {
      this._mouseDelayTimer = setTimeout(function() {
        that.mouseDelayMet = true;
      }, this.options.delay);
    }

    if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
      this._mouseStarted = (this._mouseStart(event) !== false);
      if (!this._mouseStarted) {
        event.preventDefault();
        return true;
      }
    }

    // Click event may never have fired (Gecko & Opera)
    if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
      $.removeData(event.target, this.widgetName + ".preventClickEvent");
    }

    // these delegates are required to keep context
    this._mouseMoveDelegate = function(event) {
      if($(event.target).is('input')) {
        console.log("INPUT MOUSEMOVE");
      }
      return that._mouseMove(event);
    };
    this._mouseUpDelegate = function(event) {
      return that._mouseUp(event);
    };

    $(FrameDocument)
      .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
      .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );

    event.preventDefault();

    mouseHandled = true;
    return true;
  },

  _mouseMove: function(event) {
    // IE mouseup check - mouseup happened when mouse was out of window
    if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
      return this._mouseUp(event);
    }
    // Iframe mouseup check - mouseup occurred in another document
    else if ( !event.which ) {
      return this._mouseUp( event );
    }

    if (this._mouseStarted) {
      this._mouseDrag(event);
      return event.preventDefault();
    }

    if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
      this._mouseStarted =
        (this._mouseStart(this._mouseDownEvent, event) !== false);
      (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
    }

    return !this._mouseStarted;
  },

  _mouseUp: function(event) {
    $(FrameDocument)
      .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
      .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );

    if (this._mouseStarted) {
      this._mouseStarted = false;

      if (event.target === this._mouseDownEvent.target) {
        $.data(event.target, this.widgetName + ".preventClickEvent", true);
      }

      this._mouseStop(event);
    }

    mouseHandled = false;
    return false;
  },

  _mouseDistanceMet: function(event) {
    return (Math.max(
        Math.abs(this._mouseDownEvent.pageX - event.pageX),
        Math.abs(this._mouseDownEvent.pageY - event.pageY)
      ) >= this.options.distance
    );
  },

  _mouseDelayMet: function(/* event */) {
    return this.mouseDelayMet;
  },

  // These are placeholder methods, to be overriden by extending plugin
  _mouseStart: function(/* event */) {},
  _mouseDrag: function(/* event */) {},
  _mouseStop: function(/* event */) {},
  _mouseCapture: function(/* event */) { return true; }
});

})(jQuery);
